#pragma once
#include <string>
#include <atomic>
#include <memory>

#define MAX_CHUNK 4 * 1024

class AbsZmqProxy
{
    protected:
    static void* context;
    static std::atomic<int> context_in_used;
    void* socket;
    public:
    AbsZmqProxy(int SOCKET_TYPE);
    virtual ~AbsZmqProxy();

    /**
     * @brief 立即关闭socket，并清空缓冲区，context使用数量减少一
     * 
     */
    void ReleaseSocket();
    void CreateNewSocket(int SOCKET_TYPE);

    /**
     * @brief 
     * 
     * @param sMsg 
     * @return int err -1 recvlen >= 0
     */
    int recv(std::string &sMsg, int flags=0);
    /**
     * @brief 
     * 
     * @param sMsg 
     * @return int err -1 recvlen >= 0
     */
    int recv(void*, std::string &sMsg, int flags=0);
    /**
     * @brief 
     * 
     * @param sMsg 
     * @return int err -1 sendlen >= 0
     */
    int send(const std::string& sMsg, int flags=0);
    /**
     * @brief 
     * 
     * @param sMsg 
     * @return int err -1 sendlen >= 0
     */
    int send(void*, const std::string& sMsg, int flags=0);
    void* getSocket(){return socket;}
    void SetLinger();
    int SetSNDHWD(int hwd);
    int SetRCVHWD(int hwd);
    int SetRCVBUF(int rcv_buff);
    int SetSNDBUF(int snd_buff);
    int SetRATE(int rate);
    int SetRECOVERYIVL(int ivl);
    int KeepLastMsg();
};

class ZmqPub : public AbsZmqProxy
{
    std::string protocal;

public:
    ZmqPub(int port, const std::string& protocal  = "tcp");
    ~ZmqPub();

    int pub(const std::string& channel, const std::string& sMsg, int flags=0);
    int unpacking_pub(const std::string& channel, const std::string& sMsg);
    // void* getSocket(){return socket;};
};

class ZmqRep: public AbsZmqProxy
{
    std::string protocal;

public:
    ZmqRep(int port, const std::string& protocal  = "tcp");
    ~ZmqRep();

    /**
     * @brief 用于接收客户端发来的请求，zmq要求必需与response公用
     * 
     * @param sMsg 
     * @return int 
     */
    int recv(std::string& sMsg);
    int response(std::string&& sMsg);
};

class ZmqPair: public AbsZmqProxy
{
private:
    int port;
    void* sender;

public:
    explicit ZmqPair() ;
    explicit ZmqPair(int port);
    ~ZmqPair();
    void SetPort(int port) {this->port = port;}
    int CreateRecevier();
    


    /**
     * @brief 
     * 
     * @param sMsg 
     * @return int err -1 recvlen >= 0
     */
    int recv(std::string& sMsg, int flags=0);
    /**
     * @brief 
     * 
     * @param sMsg 
     * @return int err -1 sendlen >= 0
     */
    int send(const std::string& ip, const std::string& sMsg, int flags=0);
};

